package com.example.address.service;

import com.example.address.DTO.LocationCondition;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.stereotype.Component;
import software.amazon.awssdk.services.location.LocationClient;
import software.amazon.awssdk.services.location.LocationClientBuilder;
import software.amazon.awssdk.services.location.model.SearchForTextResult;
import software.amazon.awssdk.services.location.model.SearchPlaceIndexForTextRequest;
import software.amazon.awssdk.services.location.model.SearchPlaceIndexForTextResponse;

import java.util.ArrayList;
import java.util.List;

@Data
@AllArgsConstructor
@Component
public class LocationGetter {
    private LocationClientBuilder clientBuilder;
    private SearchPlaceIndexForTextRequest.Builder requestBuilder;

    public LocationGetter() {
        ConfigurationAws configurationAws = new ConfigurationAws();
        String placeIndex = configurationAws.getPlaceIndex();
        String placeApiKey = configurationAws.getPlaceApiKey();

        clientBuilder = LocationClient.builder()
                .credentialsProvider(configurationAws.getProvider())
                .region(configurationAws.getRegion());

        requestBuilder = SearchPlaceIndexForTextRequest.builder()
                .indexName(placeIndex).key(placeApiKey);

    }

    public void setPlaceIndex(String placeIndex) {
        requestBuilder.indexName(placeIndex);
    }

    public void setAPIkey(String apiKey) {
        requestBuilder.key(apiKey);
    }

    // input text, get the point List
    public List<List<Double>>
    getPoints(@Valid LocationCondition lc) {
        LocationClient locationClient = clientBuilder.build();

        // get request
        SearchPlaceIndexForTextRequest searchPlaceIndexForTextRequest
                = getSearchPlaceIndexForTextRequest(lc);

        // get response
        SearchPlaceIndexForTextResponse response = locationClient
                .searchPlaceIndexForText(searchPlaceIndexForTextRequest);

        // get result
        List<List<Double>> res = new ArrayList<>();
        for (SearchForTextResult result : response.results()) {
            res.add(result.place().geometry().point());
        }

        locationClient.close();
        return res;
    }

    // input location condition, get the request
    private SearchPlaceIndexForTextRequest
    getSearchPlaceIndexForTextRequest(@Valid LocationCondition lc) {
        // set condision
        requestBuilder.biasPosition(lc.getBiasPosition())
                .filterBBox(lc.getFilterBBox())
                .filterCategories(lc.getFilterCategories())
                .filterCountries(lc.getFilterCountries())
                .language(lc.getLanguage())
                .maxResults(lc.getMaxResult())
                .text(lc.getText());//! can override it?yes

        // build request
        return requestBuilder.build();
    }

    // input location condition, get the response list
    public List<List<SearchForTextResult>>
    getPlacesResults(@Valid List<LocationCondition> lcList) {
        LocationClient locationClient = clientBuilder.build();

        List<List<SearchForTextResult>> res = new ArrayList<>();

        for (LocationCondition lc : lcList) {
            SearchPlaceIndexForTextResponse response
                    = locationClient.searchPlaceIndexForText(
                    getSearchPlaceIndexForTextRequest(lc)
            );
            res.add(response.results());
        }

        locationClient.close();
        return res;
    }

    // input text, get the point
    public List<Double> getPoint(String text) {
        List<List<Double>> res = getPoints(new LocationCondition(text));
        if (res.isEmpty()) {
            return new ArrayList<Double>();
        } else {
            return res.get(0);
        }
    }

}
